home *** CD-ROM | disk | FTP | other *** search
/ 3D GFX / 3D GFX.iso / amiutils / i_l / irit5 / geom_lib / primitiv.c < prev   
C/C++ Source or Header  |  1995-12-30  |  64KB  |  1,520 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d (not only polygonal) solid modeller.             *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. *   Module to generate the geometric primitives defined in the system. The   *
  7. * primitives currently defined are:                         *
  8. * 1. BOX - main planes parallel box.                         *
  9. * 2. GBOX - generalized box - 6 arbitrary planes.                 *
  10. * 3. CYLIN - cylinder with any main direction.                     *
  11. * 4. CONE, CONE2 - cone with any main direction (two bases).             *
  12. * 5. SPHERE                                     *
  13. * 6. TORUS - with any main direction.                         *
  14. * 7. PLANE - non closed, single polygon object: circle with resolution edges *
  15. * 8. POLY - directly define single polygon object by specifing its vertices. *
  16. *   In addition, the following lower level operations are defined to create  *
  17. * objects - EXTRUDE, and SURFREV, both require a polygon and a vector to     *
  18. * extrude/rotate the polygon along.                         *
  19. *****************************************************************************/
  20.  
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include "irit_sm.h"
  24. #include "geomat3d.h"
  25. #include "allocate.h"
  26. #include "attribut.h"
  27. #include "convex.h"
  28. #include "primitiv.h"
  29.  
  30. #define    MIN_RESOLUTION 4
  31.  
  32. static int GlblResolution = 16;
  33.  
  34. static IPPolygonStruct *GenInsidePoly(IPPolygonStruct *Pl);
  35. static IPPolygonStruct *GenPolygon4Vrtx(VectorType V1,
  36.                     VectorType V2,
  37.                     VectorType V3,
  38.                     VectorType V4,
  39.                     VectorType Vin,
  40.                     IPPolygonStruct *Pnext);
  41. static IPPolygonStruct *GenPolygon3Vrtx(VectorType V1,
  42.                     VectorType V2,
  43.                     VectorType V3,
  44.                     VectorType Vin,
  45.                     IPPolygonStruct *Pnext);
  46. static void UpdateVertexNormal(NormalType Normal,
  47.                    PointType Pt,
  48.                    PointType InPt,
  49.                    int Perpendicular,
  50.                    PointType PerpPt);
  51.  
  52. /*****************************************************************************
  53. * DESCRIPTION:                                                               M
  54. *   Routine to create a BOX geometric object defined by Pt - the minimum     V
  55. * 3d point, and Width - Dx Dy & Dz vector.        4             V
  56. *   Order of vertices is as                         5       7             V
  57. * follows in the picture:                           |   6   |             V
  58. *                            |   |   |             V
  59. * (Note vertex 0 is hidden behind edge 2-6)        |    |   |             V
  60. *                            1   |   3                V
  61. *                            2             V
  62. *   All dimensions can be negative, denoting the reversed direction.         M
  63. *                                                                            *
  64. * PARAMETERS:                                                                M
  65. *   Pt:          Low end corner of BOX.                                      M
  66. *   WidthX:      Width of BOX (X axis).                                      M
  67. *   WidthY:      Depth of BOX( Y axis).                                      M
  68. *   WidthZ:      Height of BOX( Z axis).                                     M
  69. *                                                                            *
  70. * RETURN VALUE:                                                              M
  71. *   IPObjectStruct *:   A BOX primitive                                      M
  72. *                                                                            *
  73. * KEYWORDS:                                                                  M
  74. *   PrimGenBOXObject, box, primitives                                        M
  75. *****************************************************************************/
  76. IPObjectStruct *PrimGenBOXObject(VectorType Pt,
  77.                  RealType WidthX,
  78.                  RealType WidthY,
  79.                  RealType WidthZ)
  80. {
  81.     VectorType Dir1, Dir2, Dir3;
  82.  
  83.     PT_CLEAR(Dir1);    Dir1[0] = WidthX;      /* Prepare direction vectors. */
  84.     PT_CLEAR(Dir2);    Dir2[1] = WidthY;       /* Parallel to main axes. */
  85.     PT_CLEAR(Dir3);    Dir3[2] = WidthZ;           /* For GBOX call. */
  86.  
  87.     return PrimGenGBOXObject(Pt, Dir1, Dir2, Dir3);
  88. }
  89.  
  90. /*****************************************************************************
  91. * DESCRIPTION:                                                               M
  92. *   Routine to create a GBOX geometric object defined by Pt - the minimum    M
  93. * 3d point, and 3 direction Vectors Dir1, Dir2, Dir3.                        M
  94. *   If two of the direction vectors are parallel the GBOX degenerates to     M
  95. * a zero volume object. A NULL pointer is returned in that case.            M
  96. *                             4             V
  97. * Order of vertices is as                           5       7             V
  98. * follows in the picture:                           |   6   |             V
  99. *                            |   |   |             V
  100. * (Note vertex 0 is hidden behind edge 2-6)        |    |   |             V
  101. *                            1   |   3                V
  102. *                            2             V
  103. *                                                                            *
  104. * PARAMETERS:                                                                M
  105. *   Pt:                Low end corner of GBOX.                     M
  106. *   Dir1, Dir2, Dir3:  Three independent directional vectors to define GBOX. M
  107. *                                                                            *
  108. * RETURN VALUE:                                                              M
  109. *   IPObjectStruct *:  A GBOX primitive.                                     M
  110. *                                                                            *
  111. * KEYWORDS:                                                                  M
  112. *   PrimGenGBOXObject, general box, box, primitives                          M
  113. *****************************************************************************/
  114. IPObjectStruct *PrimGenGBOXObject(VectorType Pt,
  115.                   VectorType Dir1,
  116.                   VectorType Dir2,
  117.                   VectorType Dir3)
  118. {
  119.     int i;
  120.     VectorType Temp;
  121.     VectorType V[8];                  /* Hold 8 vertices of BOX. */
  122.     IPVertexStruct *PVertex;
  123.     IPPolygonStruct *PPolygon;
  124.     IPObjectStruct *PBox;
  125.  
  126.     GMVecCrossProd(Temp, Dir1, Dir2);
  127.     if (APX_EQ(PT_LENGTH(Temp), 0.0))
  128.     return NULL;
  129.     GMVecCrossProd(Temp, Dir2, Dir3);
  130.     if (APX_EQ(PT_LENGTH(Temp), 0.0))
  131.     return NULL;
  132.     GMVecCrossProd(Temp, Dir3, Dir1);
  133.     if (APX_EQ(PT_LENGTH(Temp), 0.0))
  134.     return NULL;
  135.  
  136.     /* Also the 0..7 sequence is binary decoded such that bit 0 is Dir1, */
  137.     /* bit 1 Dir2, and bit 2 is Dir3 increment:                 */
  138.     for (i = 0; i < 8; i++) {
  139.     PT_COPY(V[i], Pt);
  140.  
  141.     if (i & 1)
  142.         PT_ADD(V[i], V[i], Dir1);
  143.     if (i & 2)
  144.         PT_ADD(V[i], V[i], Dir2);
  145.     if (i & 4)
  146.         PT_ADD(V[i], V[i], Dir3);
  147.     }
  148.  
  149.     PBox = GenPolyObject("", NULL, NULL); /* Generate the BOX object itself: */
  150.  
  151.     /* And generate the 6 polygons (Bottom, top and 4 sides in this order):  */
  152.     PBox -> U.Pl = GenPolygon4Vrtx(V[0], V[1], V[3], V[2], V[4], PBox -> U.Pl);
  153.     PBox -> U.Pl = GenPolygon4Vrtx(V[6], V[7], V[5], V[4], V[0], PBox -> U.Pl);
  154.     PBox -> U.Pl = GenPolygon4Vrtx(V[4], V[5], V[1], V[0], V[2], PBox -> U.Pl);
  155.     PBox -> U.Pl = GenPolygon4Vrtx(V[5], V[7], V[3], V[1], V[0], PBox -> U.Pl);
  156.     PBox -> U.Pl = GenPolygon4Vrtx(V[7], V[6], V[2], V[3], V[1], PBox -> U.Pl);
  157.     PBox -> U.Pl = GenPolygon4Vrtx(V[6], V[4], V[0], V[2], V[3], PBox -> U.Pl);
  158.  
  159.     /* Update the vertices normals using the polygon plane equation: */
  160.     for (PPolygon = PBox -> U.Pl;
  161.      PPolygon != NULL;
  162.      PPolygon = PPolygon -> Pnext) {
  163.     PVertex = PPolygon -> PVertex;
  164.     do {
  165.         PT_COPY(PVertex -> Normal, PPolygon -> Plane);
  166.         PVertex = PVertex -> Pnext;
  167.     }
  168.     while (PVertex != PPolygon -> PVertex);
  169.     }
  170.  
  171.     return PBox;
  172. }
  173.  
  174. /*****************************************************************************
  175. * DESCRIPTION:                                                               M
  176. *   Routine to create a CONE geometric object defined by Pt - the base       M
  177. * 3d center point, Dir - the cone direction and height, and base radius R.   M
  178. *   See also PrimSetResolution on fineness control of approximation of the   M
  179. * primitive using flat faces.                                                M
  180. *                                                                            *
  181. * PARAMETERS:                                                                M
  182. *   Pt:         Center location of Base of CONE.                             M
  183. *   Dir:        Direction and distance from Pt to apex of CONE.              M
  184. *   R:          Radius of Base of the cone.                                  M
  185. *                                                                            *
  186. * RETURN VALUE:                                                              M
  187. *   IPObjectStruct *:    A CONE Primitive.                                   M
  188. *                                                                            *
  189. * KEYWORDS:                                                                  M
  190. *   PrimGenCONEObject, cone, primitives                                      M
  191. *****************************************************************************/
  192. IPObjectStruct *PrimGenCONEObject(VectorType Pt, VectorType Dir, RealType R)
  193. {
  194.     int i;
  195.     RealType Angle, AngleStep;
  196.     PointType LastCirclePt, CirclePt, ApexPt;
  197.     NormalType LastCircleNrml, CircleNrml, ApexNrml;
  198.     MatrixType Mat;
  199.     IPVertexStruct *VBase, *PVertex;
  200.     IPPolygonStruct *PBase;
  201.     IPObjectStruct *PCone;
  202.  
  203.     CGGenTransMatrixZ2Dir(Mat, Pt, Dir, R);   /* Transform from unit circle. */
  204.  
  205.     PT_COPY(ApexPt, Pt);           /* Find the apex point: Pt + Dir. */
  206.     PT_ADD(ApexPt, ApexPt, Dir);
  207.     PT_NORMALIZE(Dir);
  208.  
  209.     PCone = GenPolyObject("", NULL, NULL);   /* Gen. the CONE object itself: */
  210.     /* Also allocate the base polygon header with first vertex on it: */
  211.     PBase = IPAllocPolygon(0, 0, VBase = IPAllocVertex(0, 0, NULL, NULL), NULL);
  212.  
  213.     LastCirclePt[0] = 1.0;        /* First point is allways Angle = 0. */
  214.     LastCirclePt[1] = 0.0;
  215.     LastCirclePt[2] = 0.0;
  216.     MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
  217.  
  218.     UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, TRUE, ApexPt);
  219.  
  220.     PT_COPY(VBase -> Coord, LastCirclePt);/* Update first pt in base polygon.*/
  221.     PT_COPY(VBase -> Normal, Dir);
  222.  
  223.     AngleStep = M_PI * 2 / GlblResolution;
  224.  
  225.     for (i = 1; i <= GlblResolution; i++) {   /* Pass the whole base circle. */
  226.     Angle = AngleStep * i;             /* Prevent from additive error. */
  227.  
  228.     CirclePt[0] = cos(Angle);
  229.     CirclePt[1] = sin(Angle);
  230.     CirclePt[2] = 0.0;
  231.     MatMultVecby4by4(CirclePt, CirclePt, Mat);
  232.  
  233.      UpdateVertexNormal(CircleNrml, CirclePt, Pt, TRUE, ApexPt);
  234.  
  235.     PCone -> U.Pl = GenPolygon3Vrtx(LastCirclePt, ApexPt,
  236.                           CirclePt, Pt, PCone -> U.Pl);
  237.  
  238.     /* Update the normals for this cone side polygon vertices: */
  239.     PVertex = PCone -> U.Pl -> PVertex;
  240.     PT_COPY(PVertex -> Normal, LastCircleNrml);
  241.     IP_SET_NORMAL_VRTX(PVertex);
  242.     PVertex = PVertex -> Pnext;
  243.     /* The apex normal is the average of the two base vertices: */
  244.     PT_ADD(ApexNrml, CircleNrml, LastCircleNrml);
  245.     PT_NORMALIZE(ApexNrml);
  246.     PT_COPY(PVertex -> Normal, ApexNrml);
  247.     IP_SET_NORMAL_VRTX(PVertex);
  248.     PVertex = PVertex -> Pnext;
  249.     PT_COPY(PVertex -> Normal, CircleNrml);
  250.     IP_SET_NORMAL_VRTX(PVertex);
  251.  
  252.     /* And add this vertex to base polygon: */
  253.     if (i == GlblResolution)       /* Its last point - make it circular. */
  254.         VBase -> Pnext = PBase -> PVertex;
  255.     else {
  256.         VBase -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  257.         VBase = VBase -> Pnext;
  258.         PT_COPY(VBase -> Normal, Dir);
  259.         PT_COPY(VBase -> Coord, CirclePt);
  260.     }
  261.  
  262.     PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
  263.     PT_COPY(LastCircleNrml, CircleNrml);
  264.     }
  265.  
  266.     /* Update base polygon plane equation. */
  267.     IritPrsrUpdatePolyPlane2(PBase, ApexPt);
  268.     IP_SET_CONVEX_POLY(PBase);               /* Mark it as convex polygon. */
  269.     PBase -> Pnext = PCone -> U.Pl;  /* And stick it into the cone polygons. */
  270.     PCone -> U.Pl = PBase;
  271.  
  272.     return PCone;
  273. }
  274.  
  275. /*****************************************************************************
  276. * DESCRIPTION:                                                               M
  277. *   Routine to create a truncated CONE, CON2, geometric object defined by    M
  278. * Pt - the base 3d center point, Dir - the cone direction and height, and    M
  279. * two base radii R1 and R2.                             M
  280. *   See also PrimSetResolution on fineness control of approximation of the   M
  281. * primitive using flat faces.                                                M
  282. *                                                                            *
  283. * PARAMETERS:                                                                M
  284. *   Pt:      Center location of Base of CON2.                                M
  285. *   Dir:     Direction and distance from Pt to center of other base of CON2. M
  286. *   R1, R2:  Two base radii of the truncated CON2                            M
  287. *                                                                            *
  288. * RETURN VALUE:                                                              M
  289. *   IPObjectStruct *:    A CON2 Primitive.                                   M
  290. *                                                                            *
  291. * KEYWORDS:                                                                  M
  292. *   PrimGenCONE2Object, cone, primitives                                     M
  293. *****************************************************************************/
  294. IPObjectStruct *PrimGenCONE2Object(VectorType Pt,
  295.                    VectorType Dir,
  296.                    RealType R1,
  297.                    RealType R2)
  298. {
  299.     int i;
  300.     RealType Angle, AngleStep;
  301.     PointType LastCirclePt, CirclePt, ApexPt, LastApexPt1, ApexPt1;
  302.     NormalType LastCircleNrml, CircleNrml;
  303.     VectorType InvDir;
  304.     MatrixType Mat1, Mat2;
  305.     IPVertexStruct *VBase1, *VBase2, *PVertex;
  306.     IPPolygonStruct *PBase1, *PBase2;
  307.     IPObjectStruct *PCone;
  308.  
  309.     PT_COPY(ApexPt, Pt);           /* Find the apex point: Pt + Dir. */
  310.     PT_ADD(ApexPt, ApexPt, Dir);
  311.     PT_NORMALIZE(Dir);
  312.     PT_COPY(InvDir, Dir);
  313.     PT_SCALE(InvDir, -1.0);
  314.  
  315.     CGGenTransMatrixZ2Dir(Mat1, Pt, Dir, R1);    /* Trans. from unit circle. */
  316.     CGGenTransMatrixZ2Dir(Mat2, ApexPt, Dir, R2);
  317.  
  318.     PCone = GenPolyObject("", NULL, NULL);   /* Gen. the CONE object itself: */
  319.     /* Also allocate the base polygon header with first vertex on it: */
  320.     PBase1 = IPAllocPolygon(0, 0,
  321.                 VBase1 = IPAllocVertex(0, 0, NULL, NULL), NULL);
  322.     PBase2 = IPAllocPolygon(0, 0,
  323.                 VBase2 = IPAllocVertex(0, 0, NULL, NULL), NULL);
  324.  
  325.     /* First point is allways at Angle = 0. */
  326.     LastCirclePt[0] = LastApexPt1[0] = 1.0;
  327.     LastCirclePt[1] = LastApexPt1[1] = 0.0;
  328.     LastCirclePt[2] = LastApexPt1[2] = 0.0;
  329.     MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat1);
  330.     MatMultVecby4by4(LastApexPt1, LastApexPt1, Mat2);
  331.  
  332.     UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, TRUE, ApexPt);
  333.  
  334.     PT_COPY(VBase1 -> Coord, LastCirclePt);/* Update 1st pt in base1 polygon.*/
  335.     PT_COPY(VBase1 -> Normal, Dir);
  336.     PT_COPY(VBase2 -> Coord, LastApexPt1);/* Update 1st pt in base2 polygon. */
  337.     PT_COPY(VBase2 -> Normal, InvDir);
  338.  
  339.     AngleStep = M_PI * 2 / GlblResolution;
  340.  
  341.     for (i = 1; i <= GlblResolution; i++) {   /* Pass the whole base circle. */
  342.     Angle = AngleStep * i;             /* Prevent from additive error. */
  343.  
  344.     CirclePt[0] = ApexPt1[0] = cos(Angle);
  345.     CirclePt[1] = ApexPt1[1] = sin(Angle);
  346.     CirclePt[2] = ApexPt1[2] = 0.0;
  347.     MatMultVecby4by4(CirclePt, CirclePt, Mat1);
  348.     MatMultVecby4by4(ApexPt1, ApexPt1, Mat2);
  349.  
  350.      UpdateVertexNormal(CircleNrml, CirclePt, Pt, TRUE, ApexPt);
  351.  
  352.     PCone -> U.Pl = GenPolygon4Vrtx(LastCirclePt, LastApexPt1, ApexPt1,
  353.                       CirclePt, Pt, PCone -> U.Pl);
  354.  
  355.     /* Update the normals for this cone side polygon vertices: */
  356.     PVertex = PCone -> U.Pl -> PVertex;
  357.     PT_COPY(PVertex -> Normal, LastCircleNrml);
  358.     IP_SET_NORMAL_VRTX(PVertex);
  359.     PVertex = PVertex -> Pnext;
  360.     PT_COPY(PVertex -> Normal, LastCircleNrml );
  361.     IP_SET_NORMAL_VRTX(PVertex);
  362.     PVertex = PVertex -> Pnext;
  363.     PT_COPY(PVertex -> Normal, CircleNrml);
  364.     IP_SET_NORMAL_VRTX(PVertex);
  365.     PVertex = PVertex -> Pnext;
  366.     PT_COPY(PVertex -> Normal, CircleNrml);
  367.     IP_SET_NORMAL_VRTX(PVertex);
  368.  
  369.     /* And add these vertices to base polygons: */
  370.     if (i == GlblResolution) {     /* Its last point - make it circular. */
  371.         VBase1 -> Pnext = PBase1 -> PVertex;
  372.         VBase2 -> Pnext = PBase2 -> PVertex;
  373.     }
  374.     else {
  375.         VBase1 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  376.         VBase1 = VBase1 -> Pnext;
  377.         PT_COPY(VBase1 -> Coord, CirclePt);
  378.         PT_COPY(VBase1 -> Normal, Dir);
  379.         VBase2 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  380.         VBase2 = VBase2 -> Pnext;
  381.         PT_COPY(VBase2 -> Coord, ApexPt1);
  382.         PT_COPY(VBase2 -> Normal, InvDir);
  383.     }
  384.  
  385.     PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
  386.     PT_COPY(LastApexPt1, ApexPt1);
  387.     PT_COPY(LastCircleNrml, CircleNrml);
  388.     }
  389.  
  390.     /* Update base polygon plane equation. */
  391.     IritPrsrUpdatePolyPlane2(PBase1, ApexPt);
  392.     IP_SET_CONVEX_POLY(PBase1);               /* Mark it as convex polygon. */
  393.     /* Update base polygon plane equation. */
  394.     IritPrsrUpdatePolyPlane2(PBase2, Pt);
  395.     IP_SET_CONVEX_POLY(PBase2);               /* Mark it as convex polygon. */
  396.  
  397.     PBase1 -> Pnext = PCone -> U.Pl;    /* And stick into the cone polygons. */
  398.     PCone -> U.Pl = PBase1;
  399.     PBase2 -> Pnext = PCone -> U.Pl;
  400.     PCone -> U.Pl = PBase2;
  401.  
  402.     return PCone;
  403. }
  404.  
  405. /*****************************************************************************
  406. * DESCRIPTION:                                                               M
  407. *   Routine to create a CYLINder geometric object defined by Pt - the base   M
  408. * 3d center point, Dir - the cylinder direction and height, and radius R.    M
  409. *   See also PrimSetResolution on fineness control of approximation of the   M
  410. * primitive using flat faces.                                                M
  411. *                                                                            *
  412. * PARAMETERS:                                                                M
  413. *   Pt:         Center location of Base of CYLINder.                         M
  414. *   Dir:        Direction and distance from Pt to other base of cylinder.    M
  415. *   R:          Radius of Base of the cylinder.                              M
  416. *                                                                            *
  417. * RETURN VALUE:                                                              M
  418. *   IPObjectStruct *:    A CYLINDER Primitive.                               M
  419. *                                                                            *
  420. * KEYWORDS:                                                                  M
  421. *   PrimGenCYLINObject, cylinder, primitives                                 M
  422. *****************************************************************************/
  423. IPObjectStruct *PrimGenCYLINObject(VectorType Pt, VectorType Dir, RealType R)
  424. {
  425.     int i;
  426.     RealType Angle, AngleStep;
  427.     PointType LastCirclePt, CirclePt, TLastCirclePt, TCirclePt, TPt, Dummy;
  428.     VectorType ForwardDir, BackwardDir;
  429.     NormalType LastCircleNrml, CircleNrml;
  430.     MatrixType Mat;
  431.     IPVertexStruct *VBase1, *VBase2, *PVertex;
  432.     IPPolygonStruct *PBase1, *PBase2;
  433.     IPObjectStruct *PCylin;
  434.  
  435.     CGGenTransMatrixZ2Dir(Mat, Pt, Dir, R);   /* Transform from unit circle. */
  436.  
  437.     PCylin = GenPolyObject("", NULL, NULL); /* Gen. the CYLIN object itself: */
  438.     /* Also allocate the bases polygon header with first vertex on it: */
  439.     PBase1 = IPAllocPolygon(0, 0,
  440.                 VBase1 = IPAllocVertex(0, 0, NULL, NULL), NULL);
  441.     PBase2 = IPAllocPolygon(0, 0,
  442.                 VBase2 = IPAllocVertex(0, 0, NULL, NULL), NULL);
  443.  
  444.     PT_ADD(TPt, Pt, Dir);           /* Translated circle center (by Dir). */
  445.  
  446.     /* Prepare the normal directions for the two bases: */
  447.     PT_COPY(ForwardDir, Dir);
  448.     PT_NORMALIZE(ForwardDir);
  449.     PT_COPY(BackwardDir, ForwardDir);
  450.     PT_SCALE(BackwardDir, -1.0);
  451.  
  452.     LastCirclePt[0] = 1.0;        /* First point is allways Angle = 0. */
  453.     LastCirclePt[1] = 0.0;
  454.     LastCirclePt[2] = 0.0;
  455.     MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
  456.  
  457.     UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, FALSE, Dummy);
  458.  
  459.     PT_COPY(VBase1 -> Coord, LastCirclePt);/* Update 1st pt in base1 polygon.*/
  460.     PT_COPY(VBase1 -> Normal, ForwardDir);
  461.     PT_ADD(TLastCirclePt, LastCirclePt, Dir); /* Translated circle (by Dir). */
  462.     PT_COPY(VBase2 -> Coord, TLastCirclePt);/*Update 1st pt in base2 polygon.*/
  463.     PT_COPY(VBase2 -> Normal, BackwardDir);
  464.  
  465.     AngleStep = M_PI * 2 / GlblResolution;
  466.  
  467.     for (i = 1; i <= GlblResolution; i++) {   /* Pass the whole base circle. */
  468.     Angle = AngleStep * i;             /* Prevent from additive error. */
  469.  
  470.     CirclePt[0] = cos(Angle);
  471.     CirclePt[1] = sin(Angle);
  472.     CirclePt[2] = 0.0;
  473.     MatMultVecby4by4(CirclePt, CirclePt, Mat);
  474.  
  475.     UpdateVertexNormal(CircleNrml, CirclePt, Pt, FALSE, Dummy);
  476.  
  477.     PT_ADD(TCirclePt, CirclePt, Dir);     /* Translated circle (by Dir). */
  478.  
  479.     PCylin -> U.Pl = GenPolygon4Vrtx(TLastCirclePt, TCirclePt, CirclePt,
  480.                      LastCirclePt, Pt, PCylin -> U.Pl);
  481.     /* Update the normals for this cylinder side polygon vertices: */
  482.     PVertex = PCylin -> U.Pl -> PVertex;
  483.     PT_COPY(PVertex -> Normal, LastCircleNrml);
  484.     IP_SET_NORMAL_VRTX(PVertex);
  485.     PVertex = PVertex -> Pnext;
  486.     PT_COPY(PVertex -> Normal, CircleNrml);
  487.     IP_SET_NORMAL_VRTX(PVertex);
  488.     PVertex = PVertex -> Pnext;
  489.     PT_COPY(PVertex -> Normal, CircleNrml);
  490.     IP_SET_NORMAL_VRTX(PVertex);
  491.     PVertex = PVertex -> Pnext;
  492.     PT_COPY(PVertex -> Normal, LastCircleNrml);
  493.     IP_SET_NORMAL_VRTX(PVertex);
  494.  
  495.     /* And add this vertices to the two cylinder bases:              */
  496.     /* Note Base1 is build forward, while Base2 is build backward so it  */
  497.     /* will be consistent - cross product of 2 consecutive edges will    */
  498.     /* point into the model.                         */
  499.     if (i == GlblResolution) {     /* Its last point - make it circular. */
  500.         VBase1 -> Pnext = PBase1 -> PVertex;
  501.         VBase2 -> Pnext = PBase2 -> PVertex;
  502.     }
  503.     else {
  504.         VBase1 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  505.         VBase1 = VBase1 -> Pnext;
  506.         PT_COPY(VBase1 -> Coord, CirclePt);
  507.         PT_COPY(VBase1 -> Normal, ForwardDir);
  508.         PBase2 -> PVertex = IPAllocVertex(0, 0, NULL, PBase2 -> PVertex);
  509.         PT_COPY(PBase2 -> PVertex -> Coord, TCirclePt);
  510.         PT_COPY(PBase2 -> PVertex -> Normal, BackwardDir);
  511.     }
  512.  
  513.     PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
  514.     PT_COPY(TLastCirclePt, TCirclePt);
  515.     PT_COPY(LastCircleNrml, CircleNrml);
  516.     }
  517.  
  518.     /* Update base polygon plane equation. */
  519.     IritPrsrUpdatePolyPlane2(PBase1, TPt);
  520.     IP_SET_CONVEX_POLY(PBase1);               /* Mark it as convex polygon. */
  521.     PBase1 -> Pnext = PCylin -> U.Pl;   /* And stick it into cylin polygons. */
  522.     PCylin -> U.Pl = PBase1;
  523.     /* Update base polygon plane equation. */
  524.     IritPrsrUpdatePolyPlane2(PBase2, Pt);
  525.     IP_SET_CONVEX_POLY(PBase2);               /* Mark it as convex polygon. */
  526.     PBase2 -> Pnext = PCylin -> U.Pl;   /* And stick it into cylin polygons. */
  527.     PCylin -> U.Pl = PBase2;
  528.  
  529.     return PCylin;
  530. }
  531.  
  532. /*****************************************************************************
  533. * DESCRIPTION:                                                               M
  534. *   Routine to create a SPHERE geometric object defined by Center, the       M
  535. * center of the sphere and R, its radius.                     M
  536. *   See also PrimSetResolution on fineness control of approximation of the   M
  537. * primitive using flat faces.                                                M
  538. *                                                                            *
  539. * PARAMETERS:                                                                M
  540. *   Center:   Center location of SPHERE.                                     M
  541. *   R         Radius of sphere.                                              M
  542. *                                                                            *
  543. * RETURN VALUE:                                                              M
  544. *   IPObjectStruct *:    A SPHERE Primitive.                                 M
  545. *                                                                            *
  546. * KEYWORDS:                                                                  M
  547. *   PrimGenSPHEREObject, sphere, primitives                                  M
  548. *****************************************************************************/
  549. IPObjectStruct *PrimGenSPHEREObject(VectorType Center, RealType R)
  550. {
  551.     int i, j, k;
  552.     RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
  553.     CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
  554.     PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt, Dummy;
  555.     IPVertexStruct *PVertex;
  556.     IPObjectStruct *PSphere;
  557.  
  558.     PSphere = GenPolyObject("", NULL, NULL);/* Gen the SPHERE object itself: */
  559.  
  560.     TetaAngleStep = M_PI * 2.0 / GlblResolution;     /* Runs from 0 to 2*PI. */
  561.     FeeAngleStep = M_PI * 2.0 / GlblResolution;    /* Runs from -PI/2 yo +PI/2. */
  562.  
  563.     /* Generate the lowest (south pole) triangular polygons: */
  564.     FeeAngle = (-M_PI/2.0) + FeeAngleStep; /* First circle above south pole. */
  565.     CosFeeAngle1 = cos(FeeAngle) * R;
  566.     SinFeeAngle1 = sin(FeeAngle) * R;
  567.     PT_COPY(LastCirclePt, Center);        /* Calculate the south pole. */
  568.     LastCirclePt[2] -= R;
  569.     PT_COPY(CircleLastPt, Center);    /* Calc. last point on current circle. */
  570.     CircleLastPt[0] += CosFeeAngle1;
  571.     CircleLastPt[2] += SinFeeAngle1;
  572.  
  573.     for (i = 1; i <= GlblResolution; i++) {/* Pass whole (horizontal) circle.*/
  574.     TetaAngle = TetaAngleStep * i;         /* Prevent from additive error. */
  575.  
  576.     PT_COPY(CirclePt, Center); /* Calc. current point on current circle. */
  577.     CirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
  578.     CirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
  579.     CirclePt[2] += SinFeeAngle1;
  580.  
  581.     PSphere -> U.Pl = GenPolygon3Vrtx(LastCirclePt, CircleLastPt,
  582.                     CirclePt, Center, PSphere -> U.Pl);
  583.     /* Update normals: */
  584.     for (j = 0, PVertex = PSphere -> U.Pl -> PVertex;
  585.          j < 3;
  586.          j++, PVertex = PVertex -> Pnext) {
  587.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
  588.                                 FALSE, Dummy);
  589.         IP_SET_NORMAL_VRTX(PVertex);
  590.     }
  591.  
  592.     PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
  593.     }
  594.  
  595.     /* Generate the middle rectangular polygons: */
  596.     for (i = 1; i < GlblResolution / 2 - 1; i++) {/* For all horiz. circles. */
  597.     FeeAngle = (-M_PI/2.0) + FeeAngleStep * i;
  598.     CosFeeAngle1 = cos(FeeAngle) * R;
  599.     SinFeeAngle1 = sin(FeeAngle) * R;
  600.     FeeAngle = (-M_PI/2.0) + FeeAngleStep * (i + 1);
  601.     CosFeeAngle2 = cos(FeeAngle) * R;
  602.     SinFeeAngle2 = sin(FeeAngle) * R;
  603.     PT_COPY(CircleLastPt, Center);/* Calc. last point on current circle. */
  604.     CircleLastPt[0] += CosFeeAngle2;
  605.     CircleLastPt[2] += SinFeeAngle2;
  606.     PT_COPY(LastCircleLastPt, Center);/* Calc. last point on last circle.*/
  607.     LastCircleLastPt[0] += CosFeeAngle1;
  608.     LastCircleLastPt[2] += SinFeeAngle1;
  609.  
  610.     for (j = 1; j <= GlblResolution; j++) {/* Pass whole (horiz.) circle.*/
  611.         TetaAngle = TetaAngleStep * j;   /* Prevent from additive error. */
  612.  
  613.         PT_COPY(CirclePt, Center);/* Calc. current pt on current circle. */
  614.         CirclePt[0] += cos(TetaAngle) * CosFeeAngle2;
  615.         CirclePt[1] += sin(TetaAngle) * CosFeeAngle2;
  616.         CirclePt[2] += SinFeeAngle2;
  617.         PT_COPY(LastCirclePt, Center);/* Calc. current pt on last circle.*/
  618.         LastCirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
  619.         LastCirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
  620.         LastCirclePt[2] += SinFeeAngle1;
  621.  
  622.         PSphere -> U.Pl = GenPolygon4Vrtx(LastCirclePt, LastCircleLastPt,
  623.             CircleLastPt, CirclePt, Center, PSphere -> U.Pl);
  624.         /* Update normals: */
  625.         for (k = 0, PVertex = PSphere -> U.Pl -> PVertex;
  626.          k < 4;
  627.          k++, PVertex = PVertex -> Pnext) {
  628.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
  629.                                 FALSE, Dummy);
  630.         IP_SET_NORMAL_VRTX(PVertex);
  631.         }
  632.  
  633.         PT_COPY(CircleLastPt, CirclePt);          /* Save pt in last pt. */
  634.         PT_COPY(LastCircleLastPt, LastCirclePt);
  635.     }
  636.     }
  637.  
  638.     /* Generate the upper most (north pole) triangular polygons: */
  639.     FeeAngle = (M_PI/2.0) - FeeAngleStep;  /* First circle below north pole. */
  640.     CosFeeAngle1 = cos(FeeAngle) * R;
  641.     SinFeeAngle1 = sin(FeeAngle) * R;
  642.     PT_COPY(LastCirclePt, Center);        /* Calculate the north pole. */
  643.     LastCirclePt[2] += R;
  644.     PT_COPY(CircleLastPt, Center);    /* Calc. last point on current circle. */
  645.     CircleLastPt[0] += CosFeeAngle1;
  646.     CircleLastPt[2] += SinFeeAngle1;
  647.  
  648.     for (i = 1; i <= GlblResolution; i++) {/* Pass whole (horizontal) circle.*/
  649.     TetaAngle = TetaAngleStep * i;         /* Prevent from additive error. */
  650.  
  651.     PT_COPY(CirclePt, Center); /* Calc. current point on current circle. */
  652.     CirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
  653.     CirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
  654.     CirclePt[2] += SinFeeAngle1;
  655.  
  656.     PSphere -> U.Pl = GenPolygon3Vrtx(LastCirclePt, CirclePt, CircleLastPt,
  657.                         Center, PSphere -> U.Pl);
  658.  
  659.     /* Update normals: */
  660.     for (j = 0, PVertex = PSphere -> U.Pl -> PVertex;
  661.          j < 3;
  662.          j++, PVertex = PVertex -> Pnext) {
  663.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
  664.                                 FALSE, Dummy);
  665.         IP_SET_NORMAL_VRTX(PVertex);
  666.     }
  667.  
  668.     PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
  669.     }
  670.  
  671.     return PSphere;
  672. }
  673.  
  674. /*****************************************************************************
  675. * DESCRIPTION:                                                               M
  676. *   Routine to create a TORUS geometric object defined by Center - torus 3d  M
  677. * center point, the main torus plane normal Normal, major radius Rmajor and  M
  678. * minor radius Rminor (Tube radius).                         M
  679. *   Teta runs on the major circle, Fee on the minor one. Then                M
  680. * X = (Rmajor + Rminor * cos(Fee)) * cos(Teta)                     V
  681. * Y = (Rmajor + Rminor * cos(Fee)) * sin(Teta)                     V
  682. * Z = Rminor * sin(Fee)                                 V
  683. *   See also PrimSetResolution on fineness control of approximation of the   M
  684. * primitive using flat faces.                                                M
  685. *                                                                            *
  686. * PARAMETERS:                                                                M
  687. *   Center:  Center location of the TORUS primitive.                         M
  688. *   Normal:  Normal to the major plane of the torus.                         M
  689. *   Rmajor:  Major radius of torus.                                          M
  690. *   Rminor:  Minor radius of torus.                                          M
  691. *                                                                            *
  692. * RETURN VALUE:                                                              M
  693. *   IPObjectStruct *:    A TOURS Primitive.                                  M
  694. *                                                                            *
  695. * KEYWORDS:                                                                  M
  696. *   PrimGenTORUSObject, torus, primitives                                    M
  697. *****************************************************************************/
  698. IPObjectStruct *PrimGenTORUSObject(VectorType Center,
  699.                    VectorType Normal,
  700.                    RealType Rmajor,
  701.                    RealType Rminor)
  702. {
  703.     int i, j;
  704.     RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
  705.     CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
  706.     PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt,
  707.     LastInPt, InPt, Dummy;
  708.     MatrixType Mat;
  709.     IPVertexStruct *PVertex;
  710.     IPObjectStruct *PTorus;
  711.  
  712.     CGGenTransMatrixZ2Dir(Mat, Center, Normal, 1.0);/* Trans from unit circ. */
  713.  
  714.     PTorus = GenPolyObject("", NULL, NULL); /* Gen. the Torus object itself: */
  715.  
  716.     TetaAngleStep = M_PI * 2.0 / GlblResolution;     /* Runs from 0 to 2*PI. */
  717.     FeeAngleStep = M_PI * 2.0 / GlblResolution;         /* Runs from 0 to 2*PI. */
  718.  
  719.     for (i = 1; i <= GlblResolution; i++) {
  720.     FeeAngle = FeeAngleStep * (i - 1);
  721.     CosFeeAngle1 = cos(FeeAngle) * Rminor;
  722.     SinFeeAngle1 = sin(FeeAngle) * Rminor;
  723.     FeeAngle = FeeAngleStep * i;
  724.     CosFeeAngle2 = cos(FeeAngle) * Rminor;
  725.     SinFeeAngle2 = sin(FeeAngle) * Rminor;
  726.     LastCircleLastPt[0] = Rmajor + CosFeeAngle1;
  727.     LastCircleLastPt[1] = 0.0;
  728.     LastCircleLastPt[2] = SinFeeAngle1;
  729.     MatMultVecby4by4(LastCircleLastPt, LastCircleLastPt, Mat);
  730.     LastCirclePt[0] = Rmajor + CosFeeAngle2;
  731.     LastCirclePt[1] = 0.0;
  732.     LastCirclePt[2] = SinFeeAngle2;
  733.     MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
  734.     /* Point inside the object relative to this polygon: */
  735.     LastInPt[0] = Rmajor;
  736.     LastInPt[1] = 0.0;
  737.     LastInPt[2] = 0.0;
  738.     MatMultVecby4by4(LastInPt, LastInPt, Mat);
  739.  
  740.     for (j = 1; j <= GlblResolution; j++) {
  741.         TetaAngle = TetaAngleStep * j;   /* Prevent from additive error. */
  742.  
  743.         CircleLastPt[0] = (Rmajor + CosFeeAngle1) * cos(TetaAngle);
  744.         CircleLastPt[1] = (Rmajor + CosFeeAngle1) * sin(TetaAngle);
  745.         CircleLastPt[2] = SinFeeAngle1;
  746.         MatMultVecby4by4(CircleLastPt, CircleLastPt, Mat);
  747.         CirclePt[0] = (Rmajor + CosFeeAngle2) * cos(TetaAngle);
  748.         CirclePt[1] = (Rmajor + CosFeeAngle2) * sin(TetaAngle);
  749.         CirclePt[2] = SinFeeAngle2;
  750.         MatMultVecby4by4(CirclePt, CirclePt, Mat);
  751.         /* Point inside the object relative to this polygon: */
  752.         InPt[0] = Rmajor * cos(TetaAngle);
  753.         InPt[1] = Rmajor * sin(TetaAngle);
  754.         InPt[2] = 0.0;
  755.         MatMultVecby4by4(InPt, InPt, Mat);
  756.  
  757.         PTorus -> U.Pl = GenPolygon4Vrtx(CirclePt, CircleLastPt,
  758.         LastCircleLastPt, LastCirclePt, InPt, PTorus -> U.Pl);
  759.  
  760.         /* Update normals: */
  761.         PVertex = PTorus -> U.Pl -> PVertex;
  762.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, InPt,
  763.                                 FALSE, Dummy);
  764.         IP_SET_NORMAL_VRTX(PVertex);
  765.         PVertex = PVertex -> Pnext;
  766.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, InPt,
  767.                                 FALSE, Dummy);
  768.         IP_SET_NORMAL_VRTX(PVertex);
  769.         PVertex = PVertex -> Pnext;
  770.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, LastInPt,
  771.                                 FALSE, Dummy);
  772.         IP_SET_NORMAL_VRTX(PVertex);
  773.         PVertex = PVertex -> Pnext;
  774.         UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, LastInPt,
  775.                                 FALSE, Dummy);
  776.         IP_SET_NORMAL_VRTX(PVertex);
  777.  
  778.         PT_COPY(LastCirclePt, CirclePt);          /* Save pt in last pt. */
  779.         PT_COPY(LastCircleLastPt, CircleLastPt);
  780.         PT_COPY(LastInPt, InPt);
  781.     }
  782.     }
  783.  
  784.     return PTorus;
  785. }
  786.  
  787. /*****************************************************************************
  788. * DESCRIPTION:                                                               M
  789. *   Routine to create a POLYDISK geometric object defined by the normal N    M
  790. * and the translation vector T. The object is a planar disk (a circle of     M
  791. * GlblResolution points in it...) and its radius is equal to R.             M
  792. *   The normal direction is assumed to point to the inside of the object.    M
  793. *   See also PrimSetResolution on fineness control of approximation of the   M
  794. * primitive using flat faces.                                                M
  795. *                                                                            *
  796. * PARAMETERS:                                                                M
  797. *   N:         Normal to the plane this disk included in.                    M
  798. *   T:         A translation factor of the center of the disk.               M
  799. *   R:         Radius of teh disk.                                           M
  800. *                                                                            *
  801. * RETURN VALUE:                                                              M
  802. *   IPObjectStruct *:   A single polygon object - a disk.                    M
  803. *                                                                            *
  804. * KEYWORDS:                                                                  M
  805. *   PrimGenPOLYDISKObject, disk, primitives                                  M
  806. *****************************************************************************/
  807. IPObjectStruct *PrimGenPOLYDISKObject(VectorType N, VectorType T, RealType R)
  808. {
  809.     int i;
  810.     RealType Angle, AngleStep;
  811.     PointType CirclePt;
  812.     MatrixType Mat;
  813.     IPVertexStruct *V;
  814.     IPPolygonStruct *PCirc;
  815.     IPObjectStruct *PPDisk;
  816.  
  817.     CGGenTransMatrixZ2Dir(Mat, T, N, R);      /* Transform from unit circle. */
  818.     PT_NORMALIZE(N);
  819.  
  820.     PPDisk = GenPolyObject("", NULL, NULL); /* Gen. the PLANE object itself: */
  821.     PCirc = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), NULL);
  822.     PPDisk -> U.Pl = PCirc;
  823.  
  824.     CirclePt[0] = 1.0;            /* First point is allways Angle = 0. */
  825.     CirclePt[1] = 0.0;
  826.     CirclePt[2] = 0.0;
  827.     MatMultVecby4by4(CirclePt, CirclePt, Mat);
  828.     PT_COPY(V -> Coord, CirclePt);     /* Update first pt in circle polygon. */
  829.     PT_COPY(V -> Normal, N);
  830.  
  831.     AngleStep = M_PI * 2 / GlblResolution;
  832.  
  833.     for (i = 1; i <= GlblResolution; i++) {   /* Pass the whole base circle. */
  834.     Angle = AngleStep * i;             /* Prevent from additive error. */
  835.  
  836.     CirclePt[0] = cos(Angle);
  837.     CirclePt[1] = sin(Angle);
  838.     CirclePt[2] = 0.0;
  839.  
  840.     MatMultVecby4by4(CirclePt, CirclePt, Mat);
  841.  
  842.     /* And add this vertices to the two cylinder bases: */
  843.     if (i == GlblResolution) {     /* Its last point - make it circular. */
  844.         V -> Pnext = PCirc -> PVertex;
  845.     }
  846.     else {
  847.         V -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  848.         V = V -> Pnext;
  849.         PT_COPY(V -> Coord, CirclePt);
  850.         PT_COPY(V -> Normal, N);
  851.     }
  852.     }
  853.  
  854.     PT_ADD(CirclePt, CirclePt, N);   /* Make a point "IN" the circle object. */
  855.     /* Update base polygon plane equation. */
  856.     IritPrsrUpdatePolyPlane2(PCirc, CirclePt);
  857.     IP_SET_CONVEX_POLY(PCirc);               /* Mark it as convex polygon. */
  858.  
  859.     return PPDisk;
  860. }
  861.  
  862. /*****************************************************************************
  863. * DESCRIPTION:                                                               M
  864. *   Routine to create a POLYGON/LINE directly from its specified vertices.   M
  865. *   The validity of the elements in the provided list is tested to make sure M
  866. * they are vectors or points.                                                M
  867. *   No test is made to make sure all vertices are on one plane, and that no  M
  868. * two vertices are similar.                             M
  869. *                                                                            *
  870. * PARAMETERS:                                                                M
  871. *   PObjList:     List of vertices/points to construct as a polygon/line.    M
  872. *   IsPolyline:   If TRUE, make a polyline, otherwise a polygon.             M
  873. *                                                                            *
  874. * RETURN VALUE:                                                              M
  875. *   IPObjectStruct *:   A polygon/line constructed from PObjList.            M
  876. *                                                                            *
  877. * KEYWORDS:                                                                  M
  878. *   PrimGenPOLYGONObject, polygon, polyline, primitives                      M
  879. *****************************************************************************/
  880. IPObjectStruct *PrimGenPOLYGONObject(IPObjectStruct *PObjList, int IsPolyline)
  881. {
  882.     int i,
  883.     NumVertices = 0;
  884.     IPVertexStruct *V, *VHead,
  885.     *VTail = NULL;
  886.     IPPolygonStruct *PPoly;
  887.     IPObjectStruct *PObj, *PObjPoly;
  888.  
  889.     if (!IP_IS_OLST_OBJ(PObjList))
  890.     IritFatalError("GenPOLYObject: Not object list object!");
  891.  
  892.     i = 0;
  893.     while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
  894.     if (!IP_IS_VEC_OBJ(PObj) &&
  895.         !IP_IS_POINT_OBJ(PObj) &&
  896.         !IP_IS_CTLPT_OBJ(PObj)) {
  897.         IritWarningError("None vector object found in list, empty object result.");
  898.         return NULL;
  899.     }
  900.     NumVertices++;
  901.     }
  902.  
  903.     if (NumVertices < 2 + !IsPolyline) {
  904.     IritWarningError("Too few vertices, empty object result.");
  905.     return NULL;
  906.     }
  907.  
  908.     PPoly = IPAllocPolygon(0, 0, VHead = NULL, NULL);
  909.     i = 0;
  910.     while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
  911.     V = IPAllocVertex(0, 0, NULL, NULL);
  912.     if (IP_IS_VEC_OBJ(PObj))
  913.         PT_COPY(V -> Coord, PObj -> U.Vec);
  914.     else if (IP_IS_POINT_OBJ(PObj))
  915.         PT_COPY(V -> Coord, PObj -> U.Pt);
  916.     else if (IP_IS_CTLPT_OBJ(PObj)) {
  917.         IPObjectStruct
  918.             *PVec = IritPrsrCoerceObjectTo(PObj, IP_OBJ_VECTOR);
  919.  
  920.         PT_COPY(V -> Coord, PVec -> U.Vec);
  921.         IPFreeObject(PVec);
  922.     }
  923.  
  924.     if (VHead == NULL) {
  925.         PPoly -> PVertex = VHead = VTail = V;
  926.     }
  927.     else {
  928.         VTail -> Pnext = V;
  929.         VTail = V;
  930.     }
  931.     }
  932.  
  933.     PObjPoly = GenPolyObject("", NULL, NULL);    /* Gen. POLY object itself: */
  934.     PObjPoly -> U.Pl = PPoly;
  935.     if (IsPolyline) {
  936.     IP_SET_POLYLINE_OBJ(PObjPoly);
  937.     }
  938.     else {
  939.     IP_SET_POLYGON_OBJ(PObjPoly);
  940.  
  941.     VTail -> Pnext = VHead;              /* Close the vertex list loop. */
  942.  
  943.     /* Update polygon plane equation and vertices normals. */
  944.     CGPlaneFrom3Points(PPoly -> Plane, VHead -> Coord,
  945.                VHead -> Pnext -> Coord,
  946.                VHead -> Pnext -> Pnext -> Coord);
  947.     V = VHead;
  948.     do {
  949.         PT_COPY(V -> Normal, PPoly -> Plane);
  950.         V = V -> Pnext;
  951.     }
  952.     while (V != VHead);
  953.     }
  954.  
  955.     return PObjPoly;
  956. }
  957.  
  958. /*****************************************************************************
  959. * DESCRIPTION:                                                               M
  960. * Routine to create an OBJECT directly from set of sspecified polygons.      m
  961. *   No test is made for the validity of the model in any sense.             M
  962. *                                                                            *
  963. * PARAMETERS:                                                                M
  964. *   PObjList:      List of polygonal objects.                                M
  965. *                                                                            *
  966. * RETURN VALUE:                                                              M
  967. *   IPObjectStruct *:   A single object containing all polygons in all       M
  968. *                       provided objects, by a simple union.                 M
  969. *                                                                            *
  970. * KEYWORDS:                                                                  M
  971. *   PrimGenObjectFromPolyList, primitives                                    M
  972. *****************************************************************************/
  973. IPObjectStruct *PrimGenObjectFromPolyList(IPObjectStruct *PObjList)
  974. {
  975.     int i;
  976.     IPPolygonStruct *PPoly,
  977.     *PTail = NULL;
  978.     IPObjectStruct *PObj, *PObjPoly;
  979.  
  980.     if (!IP_IS_OLST_OBJ(PObjList))
  981.     IritFatalError("GenObjectFromPolyList: Not object list object!");
  982.  
  983.     i = 0;
  984.     while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
  985.     if (!IP_IS_POLY_OBJ(PObj)) {
  986.         IritWarningError("None polygon object found in list, empty object result.");
  987.         return NULL;
  988.     }
  989.     }
  990.  
  991.     PObjPoly = GenPolyObject("", NULL, NULL);/* Gen. the POLY object itself: */
  992.     i = 0;
  993.     while ((PObj = ListObjectGet(PObjList, i)) != NULL) {
  994.     if (i++ == 0) {
  995.         if (IP_IS_POLYLINE_OBJ(PObj))
  996.             IP_SET_POLYLINE_OBJ(PObjPoly);
  997.         else
  998.         IP_SET_POLYGON_OBJ(PObjPoly);
  999.     }
  1000.     else {
  1001.         if ((IP_IS_POLYLINE_OBJ(PObj) && !IP_IS_POLYLINE_OBJ(PObjPoly)) ||
  1002.         (IP_IS_POLYGON_OBJ(PObj) && !IP_IS_POLYGON_OBJ(PObjPoly))) {
  1003.         IritWarningError("Polygons mixed with polylines.");
  1004.         return NULL;
  1005.         }          
  1006.     }
  1007.  
  1008.     PPoly = CopyPolygonList(PObj -> U.Pl);
  1009.  
  1010.     if (PTail == NULL) {
  1011.         PObjPoly -> U.Pl = PPoly;
  1012.     }
  1013.     else {
  1014.         PTail -> Pnext = PPoly;
  1015.     }
  1016.     for (PTail = PPoly; PTail -> Pnext != NULL; PTail = PTail -> Pnext);
  1017.     }
  1018.  
  1019.     return PObjPoly;
  1020. }
  1021.  
  1022. /*****************************************************************************
  1023. * DESCRIPTION:                                                               *
  1024. * Not supported.                                                             *
  1025. *                                                                            *
  1026. * PARAMETERS:                                                                *
  1027. *   PObj:                                                                    *
  1028. *                                                                            *
  1029. * RETURN VALUE:                                                              *
  1030. *   IPObjectStruct *:                                                        *
  1031. *****************************************************************************/
  1032. IPObjectStruct *PrimGenCROSSECObject(IPObjectStruct *PObj)
  1033. {
  1034.     if (PObj && !IP_IS_POLY_OBJ(PObj))
  1035.     IritFatalError("CrossSec: operation on non polygonal object");
  1036.  
  1037.     IritWarningError("GenCrossSecObject not implemented");
  1038.  
  1039.     return NULL;
  1040. }
  1041.  
  1042. /*****************************************************************************
  1043. * DESCRIPTION:                                                               M
  1044. *   Routine to a create surface of revolution by rotating the given cross    M
  1045. * section along the Z axis.                             M
  1046. *   Input can either be a polygon/line or a freefrom curve object.           M
  1047. *   If input is a polyline/gon, it must never be coplanar with the Z axis.   M
  1048. *   See also PrimSetResolution on fineness control of approximation of the   M
  1049. * primitive using flat faces.                                                M
  1050. *                                                                            *
  1051. * PARAMETERS:                                                                M
  1052. *   Cross:     To rotate around the Z axis forming a surface of revolution.  M
  1053. *                                                                            *
  1054. * RETURN VALUE:                                                              M
  1055. *   IPObjectStruct *:    A surface of revolution.                            M
  1056. *                                                                            *
  1057. * KEYWORDS:                                                                  M
  1058. *   PrimGenSURFREVObject, surface of revolution, primitives                  M
  1059. *****************************************************************************/
  1060. IPObjectStruct *PrimGenSURFREVObject(IPObjectStruct *Cross)
  1061. {
  1062.     int i, j;
  1063.     RealType XYSize;
  1064.     MatrixType Mat;               /* Rotation Matrix around Z axes. */
  1065.     IPVertexStruct *V, *V1, *V1Head, *V2, *V2Head, *VIn, *VInHead;
  1066.     IPPolygonStruct *Pl1, *Pl2, *PlIn, *PlNew = NULL;
  1067.     IPObjectStruct *PSurfRev;
  1068.  
  1069.     if (!IP_IS_POLY_OBJ(Cross) && !IP_IS_CRV_OBJ(Cross)) {
  1070.     IritWarningError("Cross section is not poly/crv. Empty object result");
  1071.     return NULL;
  1072.     }
  1073.  
  1074.     if (IP_IS_POLY_OBJ(Cross)) {
  1075.     if (APX_EQ(Cross -> U.Pl -> Plane[0], 0.0) &&
  1076.         APX_EQ(Cross -> U.Pl -> Plane[1], 0.0)) {
  1077.         IritWarningError("Cross-section perpendicular to Z. Empty object result");
  1078.         return NULL;
  1079.     }
  1080.  
  1081.     Pl1 = IPAllocPolygon(0, 0,
  1082.            V1Head = CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
  1083.     PLANE_COPY(Pl1 -> Plane, Cross -> U.Pl -> Plane);
  1084.     Pl2 = IPAllocPolygon(0, 0,
  1085.            V2Head = CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
  1086.     PLANE_COPY(Pl2 -> Plane, Cross -> U.Pl -> Plane);
  1087.     PlIn = GenInsidePoly(Pl1);
  1088.     VInHead = PlIn -> PVertex;
  1089.     MatGenMatRotZ1(2.0 * M_PI / GlblResolution, Mat);
  1090.  
  1091.     for (i = 0; i < GlblResolution; i++)
  1092.     {
  1093.         V2 = V2Head;
  1094.         do {
  1095.         MatMultVecby4by4(V2 -> Coord, V2 -> Coord , Mat);
  1096.         V2 = V2 -> Pnext;
  1097.         }
  1098.         while (V2 != NULL && V2 != V2Head);
  1099.  
  1100.         V1 = V1Head;
  1101.         if (i < GlblResolution - 1) /* If this is last loop use original */
  1102.             V2 = V2Head; /* poly as we might accumulate error during the */
  1103.         else            /* transformations along the circle. */
  1104.         V2 = Cross -> U.Pl -> PVertex;
  1105.         VIn = VInHead;
  1106.  
  1107.         do {
  1108.         PlNew = GenPolygon4Vrtx(V1 -> Coord, V1 -> Pnext -> Coord,
  1109.                         V2 -> Pnext -> Coord, V2 -> Coord,
  1110.                         VIn -> Coord, PlNew);
  1111.  
  1112.             /* Update normals: */
  1113.             for (j = 0, V = PlNew -> PVertex; j < 4; j++, V = V -> Pnext) {
  1114.             V -> Normal[0] = V -> Coord[0];
  1115.             V -> Normal[1] = V -> Coord[1];
  1116.             V -> Normal[2] = 0.0;
  1117.             /* Make sure normal does not point in opposite direction.*/
  1118.             if (DOT_PROD(V -> Normal, PlNew -> Plane) < 0.0)
  1119.                 PT_SCALE(V -> Normal, -1.0);
  1120.  
  1121.             /* Since Z normal component should be fixed for all normals: */
  1122.             V -> Normal[2] = PlNew -> Plane[2];
  1123.             XYSize = APX_EQ(ABS(PlNew -> Plane[2]), 1.0) ?
  1124.                     0.0 : 1 - SQR(PlNew -> Plane[2]);
  1125.             XYSize = sqrt(XYSize / (SQR(V -> Coord[0]) +
  1126.                         SQR(V -> Coord[1])));
  1127.             V -> Normal[0] *= XYSize;
  1128.             V -> Normal[1] *= XYSize;
  1129.             }
  1130.  
  1131.             VIn = VIn -> Pnext;
  1132.             V1 = V1 -> Pnext;
  1133.             V2 = V2 -> Pnext;
  1134.         }
  1135.         while (V1 -> Pnext != NULL && V1 != V1Head);
  1136.  
  1137.         V1 = V1Head;
  1138.         do {
  1139.             MatMultVecby4by4(V1 -> Coord, V1 -> Coord , Mat);
  1140.             V1 = V1 -> Pnext;
  1141.         }
  1142.         while (V1 != NULL && V1 != V1Head);
  1143.         VIn = VInHead;
  1144.         do {
  1145.             MatMultVecby4by4(VIn -> Coord, VIn -> Coord , Mat);
  1146.             VIn = VIn -> Pnext;
  1147.         }
  1148.         while (VIn != NULL && VIn != VInHead);
  1149.         }
  1150.  
  1151.         IPFreePolygonList(PlIn);
  1152.         IPFreePolygonList(Pl1);
  1153.         IPFreePolygonList(Pl2);
  1154.  
  1155.         PSurfRev = GenPolyObject("", NULL, NULL);
  1156.     PSurfRev -> U.Pl = PlNew;
  1157.  
  1158.         return PSurfRev;
  1159.     }
  1160.     else if (IP_IS_CRV_OBJ(Cross)) {
  1161.     if (CAGD_NUM_OF_PT_COORD(Cross -> U.Crvs -> PType) < 3) {
  1162.         IritWarningError("Cross-section perpendicular to Z. Empty object result");
  1163.         return NULL;
  1164.     }
  1165.  
  1166.         PSurfRev = GenSRFObject(CagdSurfaceRev(Cross -> U.Crvs));
  1167.     return PSurfRev;
  1168.     }
  1169.     else
  1170.         return NULL;
  1171. }
  1172.  
  1173. /*****************************************************************************
  1174. * DESCRIPTION:                                                               M
  1175. *   Routine to a create an extrusion surface out of the given cross section  M
  1176. * and the given direction.                                                   M
  1177. *   Input can either be a polygon/line or a freefrom curve object.           M
  1178. *   If input is a polyline/gon, it must never be coplanar with Dir.          M
  1179. *   See also PrimSetResolution on fineness control of approximation of the   M
  1180. * primitive using flat faces.                                                M
  1181. *                                         M
  1182. * PARAMETERS:                                                                M
  1183. *   Cross:     To extrude in direction Dir.                                  M
  1184. *   Dir:       Direction and magnitude of extrusion.                         M
  1185. *                                                                            *
  1186. * RETURN VALUE:                                                              M
  1187. *   IPObjectStruct *:     An extrusion surface.                              M
  1188. *                                                                            *
  1189. * KEYWORDS:                                                                  M
  1190. *   PrimGenEXTRUDEObject, extrusion surface, primitives                      M
  1191. *****************************************************************************/
  1192. IPObjectStruct *PrimGenEXTRUDEObject(IPObjectStruct *Cross, VectorType Dir)
  1193. {
  1194.     int i;
  1195.     RealType R;
  1196.     CagdVecStruct CagdDir;
  1197.     IPVertexStruct *V1, *V1Head, *V2, *VIn;
  1198.     IPPolygonStruct *PBase1, *PBase2, *Pl, *PlIn;
  1199.     IPObjectStruct *PExtrude;
  1200.  
  1201.     if (!IP_IS_POLY_OBJ(Cross) && !IP_IS_CRV_OBJ(Cross)) {
  1202.     IritWarningError("Cross section is not poly/crv. Empty object result");
  1203.     return NULL;
  1204.     }
  1205.  
  1206.     if (IP_IS_POLY_OBJ(Cross)) {
  1207.     R = DOT_PROD(Cross -> U.Pl -> Plane, Dir);
  1208.     if (APX_EQ(R, 0.0)) {
  1209.         IritWarningError("Extrusion direction in cross-section plane. Empty object result");
  1210.         return NULL;
  1211.     }
  1212.  
  1213.     /* Prepare two bases (update their plane normal to point INDISE): */
  1214.     PBase1 = IPAllocPolygon(0, 0,
  1215.                   CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
  1216.     Pl = PBase2 = IPAllocPolygon(0, 0,
  1217.                  CopyVertexList(Cross -> U.Pl -> PVertex), PBase1);
  1218.     V1 = V1Head = PBase2 -> PVertex;
  1219.     do {
  1220.         PT_ADD(V1 -> Coord, Dir, V1 -> Coord);
  1221.         V1 = V1 -> Pnext;
  1222.     }
  1223.     while (V1 != NULL && V1 != V1Head);
  1224.     if (R > 0.0) {
  1225.         PLANE_COPY(PBase1 -> Plane, Cross -> U.Pl -> Plane);
  1226.         for (i = 0; i < 3; i++)
  1227.         PBase2 -> Plane[i] = (-Cross -> U.Pl -> Plane[i]);
  1228.         PBase2 -> Plane[3] = (-DOT_PROD(PBase2 -> Plane,
  1229.                         PBase2 -> PVertex -> Coord));
  1230.     }
  1231.     else {
  1232.         for (i = 0; i < 4; i++)
  1233.         PBase1 -> Plane[i] = (-Cross -> U.Pl -> Plane[i]);
  1234.         PLANE_COPY(PBase2 -> Plane, Cross -> U.Pl -> Plane);
  1235.         PBase2 -> Plane[3] = (-DOT_PROD(PBase2 -> Plane,
  1236.                         PBase2 -> PVertex -> Coord));
  1237.     }
  1238.  
  1239.     /* Now generate all the 4 corner polygon between the two bases: */
  1240.     V1 = V1Head = PBase1 -> PVertex;
  1241.     V2 = PBase2 -> PVertex;
  1242.     PlIn = GenInsidePoly(PBase1);
  1243.     VIn = PlIn -> PVertex;
  1244.     do {
  1245.         Pl = GenPolygon4Vrtx(V1 -> Coord, V1 -> Pnext -> Coord,
  1246.                  V2 -> Pnext -> Coord, V2 -> Coord, VIn -> Coord, Pl);
  1247.         VIn = VIn -> Pnext;
  1248.         V1 = V1 -> Pnext;
  1249.         V2 = V2 -> Pnext;
  1250.     }
  1251.     while (V1 -> Pnext != NULL && V1 != V1Head);
  1252.  
  1253.     IPFreePolygonList(PlIn);
  1254.  
  1255.     PExtrude = GenPolyObject("", NULL, NULL);
  1256.     PExtrude -> U.Pl = Pl;
  1257.  
  1258.     /* Update all the polygon vertices normals. */
  1259.     for (Pl = PExtrude -> U.Pl; Pl != NULL; Pl = Pl -> Pnext) {
  1260.         V1 = V1Head = Pl -> PVertex;
  1261.             do {
  1262.                 PT_COPY(V1 -> Normal, Pl -> Plane);
  1263.                 V1 = V1 -> Pnext;
  1264.             }
  1265.             while (V1 != NULL && V1 != V1Head);
  1266.     }
  1267.  
  1268.     return PExtrude;
  1269.     }
  1270.     else if (IP_IS_CRV_OBJ(Cross)) {
  1271.         for (i = 0; i < 3; i++)
  1272.         CagdDir.Vec[i] = Dir[i];
  1273.         PExtrude = GenSRFObject(CagdExtrudeSrf(Cross -> U.Crvs, &CagdDir));
  1274.  
  1275.         return PExtrude;
  1276.     }
  1277.     else
  1278.         return NULL;
  1279. }
  1280.  
  1281. /*****************************************************************************
  1282. * DESCRIPTION:                                                               *
  1283. *   Routine to create a pseudo polygon out of a given polygon such that each *
  1284. * vertex Vi is in the inside side of the corresponding edge ViVi+1 in the    *
  1285. * given polygon. Used in polygon generation for EXTRUDE/SURFREV operations.  *
  1286. *                                                                            *
  1287. * PARAMETERS:                                                                *
  1288. *   Pl:        Input polygon                                                 *
  1289. *                                                                            *
  1290. * RETURN VALUE:                                                              *
  1291. *   IPPolygonStruct *:  Pseudo one.                                          *
  1292. *****************************************************************************/
  1293. static IPPolygonStruct *GenInsidePoly(IPPolygonStruct *Pl)
  1294. {
  1295.     int Axes;
  1296.     RealType Dx, Dy;
  1297.     PointType Pt;
  1298.     MatrixType Mat;
  1299.     IPPolygonStruct *PlIn;
  1300.     IPVertexStruct *VHead, *V, *Vnext, *VInHead,
  1301.     *VIn = NULL;
  1302.  
  1303.     PlIn = IPAllocPolygon(0, 0, VInHead = NULL, NULL);
  1304.  
  1305.     /* Generate transformation matrix to bring polygon to a XY parallel      */
  1306.     /* plane, and transform a copy of the polygon to that plane.         */
  1307.     GenRotateMatrix(Mat, Pl -> Plane);
  1308.     /* We dont want to modify original! */
  1309.     VHead = V = CopyVertexList(Pl -> PVertex);
  1310.     Pl = IPAllocPolygon(0, 0, VHead, NULL);
  1311.     do {
  1312.     MatMultVecby4by4(V -> Coord, V -> Coord, Mat);
  1313.     V = V -> Pnext;
  1314.     }
  1315.     while (V != NULL && V != VHead);
  1316.  
  1317.     V = VHead;
  1318.     do {
  1319.     Vnext = V -> Pnext;
  1320.     Dx = ABS(V -> Coord[0] - Vnext -> Coord[0]);
  1321.     Dy = ABS(V -> Coord[1] - Vnext -> Coord[1]);
  1322.     /* Prepare middle point. */
  1323.     Pt[0] = (V -> Coord[0] + Vnext -> Coord[0]) / 2.0;
  1324.     Pt[1] = (V -> Coord[1] + Vnext -> Coord[1]) / 2.0;
  1325.     Pt[2] = V -> Coord[2];
  1326.     /* If Dx > Dy fire ray in +Y direction, otherwise in +X direction    */
  1327.     /* and if number of intersections is even (excluding the given point */
  1328.     /* itself) then that direction is the outside, otherwise, its inside.*/
  1329.     Axes = (Dx > Dy ? 1 : 0);
  1330.     if (CGPolygonRayInter(Pl, Pt, Axes) % 2 == 0) {
  1331.         /* The amount we move along Axes is not of a big meaning as long */
  1332.         /* as it is not zero, so MAX(Dx, Dy) guarantee non zero value... */
  1333.         Pt[Axes] -= MAX(Dx, Dy);
  1334.     }
  1335.     else {
  1336.         Pt[Axes] += MAX(Dx, Dy);
  1337.     }
  1338.  
  1339.     /* Now Pt holds point which is in the inside part of vertex V, Vnext.*/
  1340.     /* Put it in the pseudo inside polygon PlIn:                 */
  1341.     if (VInHead) {
  1342.         VIn -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
  1343.         VIn = VIn -> Pnext;
  1344.     }
  1345.     else {
  1346.         PlIn -> PVertex = VInHead = VIn = IPAllocVertex(0, 0, NULL, NULL);
  1347.     }
  1348.     PT_COPY(VIn -> Coord, Pt);
  1349.  
  1350.     V = Vnext;
  1351.     }
  1352.     while (V != NULL && V != VHead);
  1353.     VIn -> Pnext = VInHead;
  1354.  
  1355.     IPFreePolygonList(Pl);          /* Free copied (and trans.) vrtx list. */
  1356.  
  1357.     /* Transform PlIn to the plane where original Pl is... */
  1358.     if (!MatInverseMatrix(Mat, Mat))         /* Find the inverse matrix. */
  1359.     IritFatalError("GenInsidePoly: Inverse matrix does not exits");
  1360.     VIn = VInHead;
  1361.     do {
  1362.     MatMultVecby4by4(VIn -> Coord, VIn -> Coord, Mat);
  1363.     VIn = VIn -> Pnext;
  1364.     }
  1365.     while (VIn != NULL && VIn != VInHead);
  1366.  
  1367.     return PlIn;
  1368. }
  1369.  
  1370. /*****************************************************************************
  1371. * DESCRIPTION:                                                               *
  1372. * Routine to create a polygon out of a list of 4 vertices V1/2/3/4.         *
  1373. *   The fifth vertex is inside (actually, this is not true, as this point    *
  1374. * will be in the positive part of the plane, which only locally in the       *
  1375. * object...) the object, so the polygon's normal direction can be evaluated  *
  1376. * uniquely.                                     *
  1377. *   No test is made to make sure the 4 points are co-planar...             *
  1378. *   The points are placed in order.                                   *
  1379. *                                                                            *
  1380. * PARAMETERS:                                                                *
  1381. *   V1, V2, V3, V4:    Four vertices of the constructed polygon.             *
  1382. *   Vin:               A vertex that can be assumed to be inside the         *
  1383. *                      object for normal evaluation of the plane of polygon. *
  1384. *   Pnext:             Next is chain of polygons, in linked list.            *
  1385. *                                                                            *
  1386. * RETURN VALUE:                                                              *
  1387. *   IPPolygonStruct *: The constructed polygon.                              *
  1388. *****************************************************************************/
  1389. static IPPolygonStruct *GenPolygon4Vrtx(VectorType V1,
  1390.                     VectorType V2,
  1391.                     VectorType V3,
  1392.                     VectorType V4,
  1393.                     VectorType Vin,
  1394.                     IPPolygonStruct *Pnext)
  1395. {
  1396.     IPPolygonStruct *PPoly;
  1397.     IPVertexStruct *V;
  1398.  
  1399.     PPoly = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), Pnext);
  1400.     PT_COPY(V -> Coord, V1);
  1401.  
  1402.     V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
  1403.     PT_COPY(V -> Coord, V2);
  1404.  
  1405.     V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
  1406.     PT_COPY(V -> Coord, V3);
  1407.  
  1408.     V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
  1409.     PT_COPY(V -> Coord, V4);
  1410.  
  1411.     V -> Pnext = PPoly -> PVertex;       /* Make the Vertex list circular. */
  1412.  
  1413.     IritPrsrUpdatePolyPlane2(PPoly, Vin);       /* Update plane equation. */
  1414.  
  1415.     IP_SET_CONVEX_POLY(PPoly);               /* Mark it as convex polygon. */
  1416.  
  1417.     return PPoly;
  1418. }
  1419.  
  1420. /*****************************************************************************
  1421. * DESCRIPTION:                                                               *
  1422. * Routine to create a polygon out of a list of 3vertices V1/2/3.           *
  1423. *   The fifth vertex is inside (actually, this is not true, as this point    *
  1424. * will be in the positive part of the plane, which only locally in the       *
  1425. * object...) the object, so the polygon's normal direction can be evaluated  *
  1426. * uniquely.                                     *
  1427. *   No test is made to make sure the 4 points are co-planar...             *
  1428. *   The points are placed in order.                         *
  1429. *                                                                            *
  1430. * PARAMETERS:                                                                *
  1431. *   V1, V2, V3:    Three vertices of the constructed polygon.                *
  1432. *   Vin:           A vertex that can be assumed to be inside the             *
  1433. *                  object for normal evaluation of the plane of polygon.     *
  1434. *   Pnext:         Next is chain of polygons, in linked list.                *
  1435. *                                                                            *
  1436. * RETURN VALUE:                                                              *
  1437. *   IPPolygonStruct *: The constructed polygon.                              *
  1438. *****************************************************************************/
  1439. static IPPolygonStruct *GenPolygon3Vrtx(VectorType V1,
  1440.                     VectorType V2,
  1441.                     VectorType V3,
  1442.                     VectorType Vin,
  1443.                     IPPolygonStruct *Pnext)
  1444. {
  1445.     IPPolygonStruct *PPoly;
  1446.     IPVertexStruct *V;
  1447.  
  1448.     PPoly = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), Pnext);
  1449.     PT_COPY(V -> Coord, V1);
  1450.  
  1451.     V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
  1452.     PT_COPY(V -> Coord, V2);
  1453.  
  1454.     V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
  1455.     PT_COPY(V -> Coord, V3);
  1456.  
  1457.     V -> Pnext = PPoly -> PVertex;       /* Make the Vertex list circular. */
  1458.  
  1459.     IritPrsrUpdatePolyPlane2(PPoly, Vin);       /* Update plane equation. */
  1460.  
  1461.     IP_SET_CONVEX_POLY(PPoly);               /* Mark it as convex polygon. */
  1462.  
  1463.     return PPoly;
  1464. }
  1465.  
  1466. /*****************************************************************************
  1467. * DESCRIPTION:                                                               *
  1468. *   Routine to update the Vertex Pt normal equation. The normal should point *
  1469. * InPt but should be perpendicular to the line Pt-PerpPt if Perpendicular is *
  1470. * TRUE. THe normal is normalized to a unit length.                 *
  1471. *                                                                            *
  1472. * PARAMETERS:                                                                *
  1473. *   Normal:        To update.                                                *
  1474. *   Pt:            The normal belongs to this location.                      *
  1475. *   InPt:          To define the normal direction as InPt - Pt.              *
  1476. *   Perpendicular: If TRUE, Normal also perpedicular to PerpPt - Pt.         *
  1477. *   PerpPt:        To define perpendicular relation as PerpPt - Pt.          *
  1478. *                                                                            *
  1479. * RETURN VALUE:                                                              *
  1480. *   void                                                                     *
  1481. *****************************************************************************/
  1482. static void UpdateVertexNormal(NormalType Normal,
  1483.                    PointType Pt,
  1484.                    PointType InPt,
  1485.                    int Perpendicular,
  1486.                    PointType PerpPt)
  1487. {
  1488.     VectorType V1, V2;
  1489.  
  1490.     PT_SUB(Normal, InPt, Pt);
  1491.  
  1492.     if (Perpendicular) {
  1493.     PT_SUB(V1, PerpPt, Pt);
  1494.     GMVecCrossProd(V2, V1, Normal);
  1495.     GMVecCrossProd(Normal, V2, V1);
  1496.     }
  1497.  
  1498.     PT_NORMALIZE(Normal);
  1499. }
  1500.  
  1501. /*****************************************************************************
  1502. * DESCRIPTION:                                                               M
  1503. * Routine to set the polygonal resolution (fineness).                        M
  1504. *   Resolution sroutghly the number of edges a circular primitive will have  M
  1505. * along the entire circle.                                                   M
  1506. *                                                                            *
  1507. * PARAMETERS:                                                                M
  1508. *   Resolution:    To set as new resolution for all primitve constructors.   M
  1509. *                                                                            *
  1510. * RETURN VALUE:                                                              M
  1511. *   void                                                                     M
  1512. *                                                                            *
  1513. * KEYWORDS:                                                                  M
  1514. *   PrimSetResolution, primitives, resolution                                M
  1515. *****************************************************************************/
  1516. void PrimSetResolution(int Resolution)
  1517. {
  1518.     GlblResolution = MAX(Resolution, MIN_RESOLUTION);
  1519. }
  1520.